{183728233}: Add Lua push write#6027
Conversation
1fe3177 to
d7dd67d
Compare
roborivers
left a comment
There was a problem hiding this comment.
Cbuild submission: Success ✓.
Regression testing: 4/679 tests failed ⚠.
The first 10 failing tests are:
queuedb_rollover_noroll1_generated **quarantined**
cdb2jdbc
consumer_non_atomic_default_consumer_generated **quarantined**
fdb_compat
sc_downgrade [timeout] **quarantined**
| rc = lua_prepare_sql(sp, sql, &stmt); | ||
| if (rc == SQLITE_SCHEMA_PUSH_REMOTE_WRITE) { | ||
| rc = handle_fdb_push_write(sp->clnt, &err, 0, NULL, sql); | ||
| if (rc == -2) { |
There was a problem hiding this comment.
disable_fdb_push would run remtran, which we do not want; we can remove the retry here and simply return error (at this point push is available everywhere)
| return -1; | ||
| } | ||
| rc = cdb2_run_statement(hndl, clnt->sql); | ||
| rc = cdb2_run_statement(hndl, sql ? sql : clnt->sql); |
There was a problem hiding this comment.
we could pass clnt->sql as argument and always use sql here
d7dd67d to
2372267
Compare
2372267 to
ea9dda9
Compare
roborivers
left a comment
There was a problem hiding this comment.
Cbuild submission: Error ⚠.
Regression testing: Success ✓.
The first 10 failing tests are:
ssl_san
consumer_non_atomic_default_consumer_generated **quarantined**
fdb_compat
ssl_set_cmd
ssl_prefer
ssl_dbname
sc_downgrade [timeout] **quarantined**
sc_timepart [timeout] **quarantined**
ea9dda9 to
5bcbc89
Compare
roborivers
left a comment
There was a problem hiding this comment.
Cbuild submission: Error ⚠.
Regression testing: Success ✓.
The first 10 failing tests are:
sc_resume_logicalsc_generated **quarantined**
sp_snapshot_generated
sc_parallel_logicalsc_generated
consumer_non_atomic_default_consumer_generated **quarantined**
fdb_push_lua
fdb_compat
sc_downgrade [timeout] **quarantined**
roborivers
left a comment
There was a problem hiding this comment.
Cbuild submission: Success ✓.
Regression testing: Success ✓.
The first 10 failing tests are:
sc_resume_logicalsc_generated **quarantined**
consumer_non_atomic_default_consumer_generated **quarantined**
fdb_push_lua
manual_partition
fdb_compat
sc_downgrade [timeout] **quarantined**
28f01d5 to
ec68fcd
Compare
roborivers
left a comment
There was a problem hiding this comment.
Cbuild submission: Error ⚠.
Regression testing: Success ✓.
roborivers
left a comment
There was a problem hiding this comment.
Cbuild submission: Error ⚠.
Regression testing: Success ✓.
ec68fcd to
6c09249
Compare
roborivers
left a comment
There was a problem hiding this comment.
Cbuild submission: Error ⚠.
Regression testing: Success ✓.
roborivers
left a comment
There was a problem hiding this comment.
Cbuild submission: Success ✓.
Regression testing: Success ✓.
roborivers
left a comment
There was a problem hiding this comment.
Cbuild submission: Success ✓.
Regression testing: Success ✓.
roborivers
left a comment
There was a problem hiding this comment.
Cbuild submission: Success ✓.
Regression testing: Success ✓.
The first 10 failing tests are:
sc_redo [failed with core dumped]
sc_resume_logicalsc_generated **quarantined**
consumer_non_atomic_default_consumer_generated **quarantined**
fdb_compat
sc_downgrade [timeout] **quarantined**
6c09249 to
4c0f998
Compare
roborivers
left a comment
There was a problem hiding this comment.
Cbuild submission: Error ⚠.
Regression testing: 0/0 tests failed ⚠.
roborivers
left a comment
There was a problem hiding this comment.
Cbuild submission: Error ⚠.
Regression testing: 0/0 tests failed ⚠.
roborivers
left a comment
There was a problem hiding this comment.
Cbuild submission: Error ⚠.
Regression testing: 0/0 tests failed ⚠.
df2c0cb to
f69789d
Compare
roborivers
left a comment
There was a problem hiding this comment.
Cbuild submission: Error ⚠.
Regression testing: 0/0 tests failed ⚠.
roborivers
left a comment
There was a problem hiding this comment.
Cbuild submission: Error ⚠.
Regression testing: Success ✓.
The first 10 failing tests are:
sirace [failed with core dumped]
sc_force [failed with core dumped]
rebuild_table_options [failed with core dumped]
odh_blobs [failed with core dumped]
verify_writes [failed with core dumped]
serial_randtest2 [failed with core dumped]
sicountbug [failed with core dumped]
incremental_backup [failed with core dumped]
maxtable
phys_rep_tiered
roborivers
left a comment
There was a problem hiding this comment.
Cbuild submission: Success ✓.
Regression testing: Success ✓.
The first 10 failing tests are:
sirace [failed with core dumped]
sc_force [failed with core dumped]
odh_blobs [failed with core dumped]
rebuild_table_options [failed with core dumped]
verify_writes [failed with core dumped]
serial_randtest2 [failed with core dumped]
sicountbug [failed with core dumped]
incremental_backup [failed with core dumped]
maxtable
phys_rep_tiered
roborivers
left a comment
There was a problem hiding this comment.
Cbuild submission: Success ✓.
Regression testing: Success ✓.
The first 10 failing tests are:
simpleauth_password [setup failed]
sc_resume_logicalsc_generated **quarantined**
reco-ddlk-sql **quarantined**
consumer_non_atomic_default_consumer_generated **quarantined**
fdb_compat
sc_downgrade [timeout] **quarantined**
f69789d to
5c0ffe8
Compare
roborivers
left a comment
There was a problem hiding this comment.
Cbuild submission: Success ✓.
Regression testing: Success ✓.
The first 10 failing tests are:
sqllogfill_reset_gen
consumer_non_atomic_default_consumer_generated **quarantined**
sc_downgrade [timeout] **quarantined**
reco-ddlk-sql [timeout] **quarantined**
roborivers
left a comment
There was a problem hiding this comment.
Cbuild submission: Error ⚠.
Regression testing: Success ✓.
The first 10 failing tests are:
sc_resume_logicalsc_generated **quarantined**
ssl_san
consumer_non_atomic_default_consumer_generated **quarantined**
ssl_set_cmd
ssl_prefer
ssl_dbname
sc_downgrade [timeout] **quarantined**
5c0ffe8 to
8b6b1f1
Compare
roborivers
left a comment
There was a problem hiding this comment.
Cbuild submission: Error ⚠.
Regression testing: Success ✓.
The first 10 failing tests are:
sc_resume_logicalsc_generated **quarantined**
ssl_san
consumer_non_atomic_default_consumer_generated **quarantined**
manual_partition
ssl_set_cmd
ssl_prefer
ssl_dbname
skipscan **quarantined**
sc_downgrade [timeout] **quarantined**
reco-ddlk-sql [timeout] **quarantined**
8b6b1f1 to
b7b83f0
Compare
roborivers
left a comment
There was a problem hiding this comment.
Cbuild submission: Success ✓.
Regression testing: Success ✓.
The first 10 failing tests are:
consumer_non_atomic_default_consumer_generated **quarantined**
commit_lsn_map
sc_downgrade [timeout] **quarantined**
b7b83f0 to
e9f9670
Compare
roborivers
left a comment
There was a problem hiding this comment.
Cbuild submission: Success ✓.
Regression testing: Success ✓.
The first 10 failing tests are:
consumer_non_atomic_default_consumer_generated **quarantined**
sc_downgrade [timeout] **quarantined**
reco-ddlk-sql [timeout] **quarantined**
|
|
||
| int rc; | ||
| if (dbstmt->fdb_push) { | ||
| struct errstat err; |
| free(params); | ||
| } | ||
|
|
||
| clnt->fdb_push = push; |
There was a problem hiding this comment.
do we leak fdb_push here when we run multiple writes in same sp?
| lua_pushnil(lua); | ||
| lua_pushinteger(lua, sp->rc); | ||
| } else { | ||
| lua_pushinteger(lua, 0); |
There was a problem hiding this comment.
Claude flagged this as wrong stack: "After lua_remove(1) the stack is [sql]. On push-write success only lua_pushinteger(lua,0) is pushed, then return 2, so
Lua returns (sql_string, 0) instead of (nil, 0). Any caller doing local h, rc = db:exec("insert into remote...") gets
the SQL string (truthy) as the handle. Fix: add a leading lua_pushnil(lua) before the 0. The error branch is already
correct."
|
|
||
| struct param_data *param = &fdb_push_get_params(push)[position - 1]; | ||
| if ((param->type == CLIENT_CSTR || param->type == CLIENT_BLOB) && param->len > 0) | ||
| free(param->u.p); |
There was a problem hiding this comment.
is param->len for a empty C string 0 or 1? if it is zero, do we leak a one byte here
| fdb_push_connector_t *push = sp->clnt->fdb_push; | ||
| int nparams = sqlite3_bind_parameter_count(stmt); | ||
| if (nparams > 0) { | ||
| fdb_push_set_params(push, calloc(nparams, sizeof(struct param_data))); |
There was a problem hiding this comment.
check calloc return for NULL
| int type; | ||
| if ((type = luabb_dbtype(lua, value)) > DBTYPES_MINTYPE) { | ||
| if (luabb_isnull(lua, value)) { | ||
| param->null = 1; |
There was a problem hiding this comment.
I think we need to do something like:
1959 + switch (type) {
1960 + case DBTYPES_INTEGER: param->type = CLIENT_INT; break;
1961 + case DBTYPES_REAL: param->type = CLIENT_REAL; break;
1962 + case DBTYPES_CSTRING: param->type = CLIENT_CSTR; break;
1963 + case DBTYPES_BLOB: param->type = CLIENT_BLOB; break;
1964 + case DBTYPES_DATETIME: param->type = CLIENT_DATETIME; break;
1965 + default: param->type = CLIENT_INT; break;
1966 + }
Reproducing test case:
# ============================================================
# Test 17: bind a typed NULL (a NULL read from a query column,
# not a plain lua nil) -- reproduces typed-null bind
# ============================================================
echo "Test 17: bind typed NULL from query column" >> $output
$S - >> $output 2>&1 <<EOF
create procedure test_typed_null version 'test17' {
local function main()
-- A NULL read back from a query comes through as a *typed* null
-- (a dbtype userdata), unlike the plain lua nil used in Test 6.
local sel = db:exec("SELECT NULL as x")
local row = sel:fetch()
local stmt, rc = db:prepare("INSERT INTO LOCAL_${a_remdbname}.t2(i, r, s) VALUES (@i, @r, @s)")
if rc ~= 0 then
return db:error(rc)
end
stmt:bind('i', 200)
stmt:bind('r', 2.5)
stmt:bind('s', row.x)
stmt:exec()
end
}\$\$
exec procedure test_typed_null()
EOF
# Verify: row 200 must exist on the remote with s NULL
$R "SELECT i, r, s FROM t2 WHERE i=200" >> $output 2>&1
dorinhogea
left a comment
There was a problem hiding this comment.
please see comments, thank you
| if (!clnt->in_client_trans) { | ||
| goto free; | ||
| } |
There was a problem hiding this comment.
Follow-up (perf, non-blocking): SP push writes reconnect on every exec.
When the SP is not in an outer transaction (!clnt->in_client_trans), each push write closes its remote connection right after running (fdb_free_tran, db/fdb_push.c:820).
So this loop reconnects every time:
local stmt = db:prepare("INSERT INTO LOCAL_remdb.t VALUES (?, ?)")
for i = 1, 10000 do
stmt:bind(1, i); stmt:bind(2, 'row'..i); stmt:exec() -- reconnects each time
endGotcha: db:begin() inside the SP does not help. It doesn't set in_client_trans. Only an outer client transaction reuses the handle:
begin
exec procedure ...
commit
Fix: keep the remote connection open across execs in one SP call. Free it once at SP teardown (reset_sp). Gate it so it never double-frees a dtran owned by an outer transaction. Semantics stay the same — each write is already auto-committed remotely. We just skip the reconnect.
| if (p->nparams && p->params) | ||
| dohsql_free_params(&p->nparams, &p->params, | ||
| p->nparams-1); |
There was a problem hiding this comment.
why did we pass p->nparams-1? If the number of params is 1 does it mean we don't free anything?
Signed-off-by: Emelia Lei <wlei29@bloomberg.net>
Signed-off-by: Emelia Lei <wlei29@bloomberg.net>
e9f9670 to
1dc1952
Compare
…m leak Two bugs in the Lua push-write path, both exercised by tests/fdb_push_lua.test: 1. Shared-connector collision. All prepared push writes routed bind/exec through the single clnt->fdb_push slot, so a second db:prepare clobbered the first statement's params/remotedb. Each dbstmt now owns its connector: db:prepare detaches it from clnt->fdb_push onto dbstmt->push_conn, bind targets that connector directly (never clnt->fdb_push, which a bind-error longjmp could leave dangling), exec installs/restores it around the write, and donate_stmt frees it. Covered by Test 18 (two concurrently-prepared push statements) — fails on the old code with a bogus out-of-range bind. 2. Prepare-time param leak. When an SP is invoked with bind args, fdb_push_write_setup clones those params into the connector; db_prepare then overwrote that array with a fresh one for the statement's own placeholders, leaking the clone. db_prepare now calls the new fdb_push_clear_params() before installing its array. Covered by Test 19 (SP invoked with a bind arg + push prepare). Also downgrade two LOGMSG_WARN in fdb_push_write_setup to LOGMSG_DEBUG: the non-push fallback is normal control flow, not a warning. Signed-off-by: Emelia Lei <wlei29@bloomberg.net>
1dc1952 to
c537a5a
Compare
roborivers
left a comment
There was a problem hiding this comment.
Cbuild submission: Error ⚠.
Regression testing: Success ✓.
The first 10 failing tests are:
reco-ddlk-sql **quarantined**
ssl_san
consumer_non_atomic_default_consumer_generated **quarantined**
ssl_set_cmd
ssl_prefer
ssl_dbname
sc_downgrade [timeout] **quarantined**
roborivers
left a comment
There was a problem hiding this comment.
Cbuild submission: Success ✓.
Regression testing: Success ✓.
The first 10 failing tests are:
consumer_non_atomic_default_consumer_generated **quarantined**
sc_downgrade [timeout] **quarantined**
No description provided.